#pragma once

#include <vector>
#include "core//stringhash.h"

#define JSON_STRING_BUFFER_SIZE 16384

enum json_value_type
{
	type_num,
	type_str,
	type_hash,
	type_bool,
	type_nil,
	type_int,
	type_obj,
	type_arr,
	type_undefined
};


struct json_object_t;
struct json_array_t;

struct json_value_t
{
	json_value_t()
	{
		val_type=type_undefined;
	}
	bool is_num() const
	{
		return val_type==type_num;
	}

	bool is_int() const
	{
		return val_type==type_int;
	}

	bool is_str() const
	{
		return val_type==type_str;
	}

	bool is_hash() const
	{
		return val_type==type_hash;
	}

	bool is_bool() const
	{
		return val_type==type_bool;
	}

	bool is_nil() const
	{
		return val_type==type_nil;
	}

	bool is_object() const
	{
		return val_type==type_obj;
	}

	bool is_array() const
	{
		return val_type==type_arr;
	}

	bool is_valamilyen_num() const
	{
		return val_type==type_int || val_type==type_num;
	}

	operator float&()
	{
		ASSERT(is_num());
		return num;
	}

	operator float() const
	{
		ASSERT(is_num() || is_int());
		if (is_num())
			return num;
		else
			return (float)(int_num);
	}

	operator int&()
	{
		ASSERT(is_int());
		return int_num;
	}

	operator int() const
	{
		ASSERT(is_int() || is_num());
		if (is_int())
			return int_num;
		else
			return (int)num;
	}

	operator float2();// const
	operator float3();// const

	operator bool&()
	{
		ASSERT(is_bool());
		return b;
	}

	operator bool() const
	{
		ASSERT(is_bool());
		return b;
	}

	operator string&()
	{
		ASSERT(is_str());
		return *str;
	}

	operator string() const
	{
		ASSERT(is_str());
		return *str;
	}


	float get_num() const
	{
		ASSERT(is_num()|| is_int());
		return is_num() ? num : float(int_num);
	}



	void set_num(float n)
	{
		ASSERT(is_num() || is_int() || val_type==type_undefined);
		val_type=type_num;
		num=n;
	}

	int get_int() const
	{
		ASSERT(is_int());
		return int_num;
	}

	void set_int(int i)
	{
		ASSERT(is_int() || val_type==type_undefined);
		val_type=type_int;
		int_num=i;
	}
	const string& get_str() const
	{
		ASSERT(is_str());
		return *str;
	}
	const stringhash& get_hash() const
	{
		ASSERT(is_hash());
		return (stringhash&)hash;
	}
	void set_str(const string& s)
	{
		ASSERT(is_str() || val_type==type_undefined);
		if (is_str())
			delete str;
		val_type=type_str;
		str=new string(s);
	}

	void set_str(const char* ch)
	{
		ASSERT(is_str() || val_type==type_undefined);
		if (is_str())
			delete str;
		val_type=type_str;
		str=new string(ch);
	}

	void set_hash(const stringhash& h)
	{
		ASSERT(is_hash() || val_type==type_undefined);
		val_type=type_hash;
		(stringhash&)hash=h;
	}

	bool get_bool() const
	{
		ASSERT(is_bool());
		return b;
	}

	void set_bool(bool ib)
	{
		ASSERT(is_bool() || val_type==type_undefined);
		val_type=type_bool;
		b=ib;
	}

	json_object_t& get_object()
	{
		ASSERT(is_object());
		return *obj;
	}

	void set_object(json_object_t* o)
	{
		ASSERT(is_object());
		obj=o;
	}

	json_array_t& get_array()
	{
		ASSERT(is_array());
		return *arr;
	}

	json_object_t& create_object();
	json_array_t& create_array();

	void set_nil()
	{
		ASSERT(is_nil() || val_type==type_undefined);
		val_type=type_nil;
	}

	void free();
	void copy(const json_value_t& other);

	json_value_type get_type() const
	{
		return val_type;
	}


private:
	union
	{
		string* str;
		float num;
		bool b;
		json_object_t* obj;
		json_array_t* arr;
		int int_num;
		char hash[sizeof(stringhash)];
	};
	json_value_type val_type;
};

struct json_pair_t
{
	void free()
	{
		val.free();
	}

	stringhash key;
	json_value_t val;
};

struct json_object_t
{

	~json_object_t()
	{
		for (unsigned n=0; n<pair_list.size(); ++n)
			pair_list[n].free();
	}

	void clear()
	{
		for (unsigned n=0; n<pair_list.size(); ++n)
			pair_list[n].free();

		pair_list.clear();
	}

	uint32 size() const
	{
		return pair_list.size();
	}

	json_value_t* operator[](const stringhash& name)
	{
		return get_value(name);
	}

	json_value_t* get_value(const stringhash& name)
	{
		for (unsigned int n=0; n<pair_list.size(); ++n)
		{
			if (name==pair_list[n].key)
				return &pair_list[n].val;
		}

		return NULL;
	}

	json_array_t& get_array(const stringhash& name)
	{
		return get_value(name)->get_array();
	}

	const string& get_str(const stringhash& name)
	{
		return get_value(name)->get_str();
	}

	json_value_t* get_or_create_value(const stringhash& name)
	{
		for (unsigned int n=0; n<pair_list.size(); ++n)
		{
			if (name==pair_list[n].key)
				return &pair_list[n].val;
		}

		add(name);
		return &pair_list.back().val;
	}

	json_value_t& operator[](int index)
	{
		return pair_list[index].val;
	}

	const json_value_t& operator[](int index) const
	{
		return pair_list[index].val;
	}

	void add(const stringhash& name)
	{
		json_pair_t p;
		p.key=name;
		pair_list.push_back(p);
	}

	void add(const stringhash& name, float n)
	{
		json_pair_t p;
		p.key=name;
		p.val.set_num(n);
		pair_list.push_back(p);
	}
	void add(const stringhash& name, int n)
	{
		json_pair_t p;
		p.key=name;
		p.val.set_int(n);
		pair_list.push_back(p);
	}
	void add(const stringhash& name, bool b)
	{
		json_pair_t p;
		p.key=name;
		p.val.set_bool(b);
		pair_list.push_back(p);
	}
	void add(const stringhash& name, const string& s)
	{
		json_pair_t p;
		p.key=name;
		p.val.set_str(s);
		pair_list.push_back(p);
	}

	vector<json_pair_t> pair_list;

	void copy(const json_object_t& from)
	{
		for (unsigned n=0; n<pair_list.size() ;++n)
			pair_list[n].val.free();

		pair_list.clear();
		pair_list.resize(from.pair_list.size());

		for (unsigned n=0; n<pair_list.size(); ++n)
		{
			pair_list[n].key=from.pair_list[n].key;
			pair_list[n].val.copy(from.pair_list[n].val);
		}
	}
};

struct json_array_t
{
	~json_array_t()
	{
		for (unsigned n=0; n<value_list.size(); ++n)
			value_list[n].free();
	}

	json_value_t& operator [](int index)
	{
		return value_list[index];
	}

	uint32 size() const
	{
		return value_list.size();
	}

	const json_value_t& operator [](int index)const
	{
		return value_list[index];
	}
	void copy(const json_array_t& other)
	{
		for (unsigned n=0; n<value_list.size(); ++n)
		{
			value_list[n].free();
		}

		value_list.clear();
		value_list.resize(other.value_list.size());
		for (unsigned n=0; n<value_list.size(); ++n)
		{
			value_list[n].copy(other.value_list[n]);
		}
	}
	vector<json_value_t> value_list;
};

#ifdef LEO_DESIGNER
string save_json_to_string(json_object_t* o,bool brace=true);
#endif

json_object_t* generate_json_map(const char* filename);
json_object_t* generate_json_map_from_binary(const char* filename);
json_object_t* generate_json_map(const string& filestr);

struct valueref
{
	json_value_t* ptr;
	valueref(){ptr=NULL;}
	valueref(json_value_t* p):ptr(p){}
	float snc_dummy_1, snc_dummy_2;
};

struct objectref
{
	json_object_t* objptr;
	float snc_dummy_1, snc_dummy_2;
};
